package com.omni.monitor.plugin.trace_monitor;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.omni.monitor.model.trace_monitor.*;
import com.omni.monitor.plugin.utils.EsUtils;
import com.omni.monitor.plugin.utils.MonitorConfig;
import com.omni.monitor.plugin.utils.ReflectionUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;

import static com.omni.monitor.plugin.utils.ReflectionUtils.*;

@Service
public class TraceService {
    @Resource
    MonitorConfig monitorConfig;


    public List<TraceNode> getTraceNodeList(String traceId) {
        ServiceTraceNode traceNode_Req = new ServiceTraceNode();
        traceNode_Req.setTraceId(traceId);
        // 2. 构造查询参数（requests）
        Map<String, Object> requests = new HashMap<>();
        if (StringUtils.isNotBlank(traceId)) {
            requests.put("traceId", traceId); // 必传：traceId条件
        }
        requests.put("size", 3000); // 可选：每页条数（默认10）
        requests.put("from", 0); // 可选：分页起始位置（默认0，即第一页）

        List<TraceNode> traceNodeList = new ArrayList<>();
        TraceLogEsPageRes traceLogEsPageRes = new TraceLogEsPageRes();
        traceLogEsPageRes = getTraceFromEs(requests, "methodTree_traceId");
        traceNodeList = convertToTree(traceLogEsPageRes.getTraceNodeList());
        return traceNodeList;

    }

    /**
     * 获取所有一级入口（调用深度为1且没有父节点的）
     */
    public TraceLogEsPageRes getRootNodes(TraceLogEsReq req) {
        TraceLogEsPageRes traceLogEsPageRes = new TraceLogEsPageRes();
        List<TraceNode> rootNodes = new ArrayList<>();
        Map<String, Object> requests = new HashMap<>();
        requests.put("parentSpanId", "root_node");
        //requests.put("depth", 1);
        if (StringUtils.isNotBlank(req.getServiceName())) {
            requests.put("serviceName", req.getServiceName());
        }
        if (StringUtils.isNotBlank(req.getMethodName())) {
            requests.put("methodName", req.getMethodName());
        }
        if (StringUtils.isNotBlank(req.getTraceId())) {
            requests.put("traceId", req.getTraceId()); // 必传：traceId条件
        }

        if (req.getStartTime_began() != null && req.getStartTime_began() > 0) {
            requests.put("startTime_began", req.getStartTime_began());
        }
        if (req.getStartTime_end() != null && req.getStartTime_end() > 0) {
            requests.put("startTime_end", req.getStartTime_end());
        }
        requests.put("size", req.getSize()); // 可选：每页条数（默认10）
        requests.put("from", req.getFrom()); // 可选：分页起始位置（默认0，即第一页）
        traceLogEsPageRes = getTraceFromEs(requests, "methodTreePage");

        return traceLogEsPageRes;
    }

    public String setMonitorEnabled(String enableKey, String enabledValue) {

        String setResult = "";
        //方法树监控开关
         if ("trace-monitor-enabled".equals(enableKey)) {
            monitorConfig.setEnabled(enabledValue);
            setResult = monitorConfig.getEnabled();
        }
        //监控参数记录开关
        if ("trace-monitor-parameterSwitch".equals(enableKey)) {
            monitorConfig.setParameterSwitch(enabledValue);
            setResult = monitorConfig.getParameterSwitch();
        }
        return setResult;

    }

    /**
     * 开关获取
     *
     * @param enableKey 开关类型
     * @return 获取结果
     */
    public String getMonitorEnabled(String enableKey) {
        String setResult = "";
        //方法树监控开关
        if ("trace-monitor-enabled".equals(enableKey)) {
            setResult = monitorConfig.getEnabled();
        }
        //监控参数记录开关
        if ("trace-monitor-parameterSwitch".equals(enableKey)) {
            setResult = monitorConfig.getParameterSwitch();
        }
        return setResult;

    }

    /**
     * 从ES中获取数据
     *
     * @param requests 查询参数
     * @return 返回
     */
    private TraceLogEsPageRes getTraceFromEs(Map<String, Object> requests, String templateName) {
        TraceLogEsPageRes traceLogEsPageRes = new TraceLogEsPageRes();
        JSONObject jsonObject = EsUtils.getEsByTemplateName(monitorConfig.getEsIndexName(), monitorConfig.getEsURL(), monitorConfig.getEsToken(), requests, templateName);
        List<TraceNode> traceNodeList = new ArrayList<>();
        //搜索结果的总数量
        long total = jsonObject.getJSONObject("result").getLong("count");
        JSONArray searchHits = new JSONArray();
        searchHits = jsonObject.getJSONObject("result").getJSONArray("list");


        for (Object searchHit : searchHits) {
            TraceLogEsRes appInfo = JSONObject.parseObject(JSONObject.toJSONString(searchHit), TraceLogEsRes.class);
            traceNodeList.add(appInfo);
        }
        traceLogEsPageRes.setTraceNodeList(traceNodeList);
        traceLogEsPageRes.setTotalCount(total);
        return traceLogEsPageRes;
    }

    private List<TraceNode> convertToTree(List<TraceNode> nodeQueue) {
        // 1. 转为列表并按startTime排序（确保节点顺序符合调用时序）
        List<TraceNode> sortedNodes = nodeQueue.stream().sorted(Comparator.comparingLong(TraceNode::getStartTime)).collect(Collectors.toList());
        //对于线程池切换节点，无需输出
        // 2. 构建spanId→节点的映射（O(1)查找父节点）
        Map<String, TraceNode> spanMap = sortedNodes.stream().collect(Collectors.toMap(TraceNode::getSpanId, node -> node, (oldVal, newVal) -> newVal // 重复时取最新（理论上不会）
        ));
        // 3. 构建父子关系（移除跳过节点的错误逻辑）
        List<TraceNode> rootNodes = new ArrayList<>();
        for (TraceNode node : sortedNodes) {
            setParameterJson(node);
            String parentSpanId = node.getParentSpanId();
            if (StringUtils.isBlank(parentSpanId)) {
                rootNodes.add(node);
            } else {
                TraceNode parentNode = spanMap.get(parentSpanId);
                if (parentNode != null) {
                    if (parentNode.getServiceName().endsWith("Mapper") && StringUtils.isNotBlank(node.getSqlId()) && node.getSqlId().endsWith(parentNode.getMethodName())) {
                        parentNode.setSqlId(node.getSqlId());
                        parentNode.setFullSql(node.getFullSql());
                        parentNode.setOriginalSql(node.getOriginalSql());
                        parentNode.setCostTime(node.getCostTime() + parentNode.getCostTime());
                        parentNode.setEndTime(node.getEndTime());
                    } else {
                        //底层SQL支持执行节点
                        if (StringUtils.isBlank(node.getServiceName()) && StringUtils.isBlank(node.getMethodName()) && StringUtils.isNotBlank(node.getSqlId())) {
                            if (node.getSqlId().startsWith("INSERT")) {
                                node.setMethodName("INSERT");
                            } else if (node.getSqlId().startsWith("UPDATE")) {
                                node.setMethodName("UPDATE");
                            } else if (node.getSqlId().startsWith("DELETE")) {
                                node.setMethodName("DELETE");
                            } else if (node.getSqlId().startsWith("SELECT")) {
                                node.setMethodName("SELECT");
                            }
                        }
                        // 父节点的children需线程安全（TraceNode中定义为ConcurrentLinkedQueue）
                        parentNode.getChildren().add(node);
                    }

                } else {
                    rootNodes.add(node);
                }
            }
        }
        return rootNodes;
    }
    private void setParameterJson(TraceNode node) {
        if (node.getParameters().size() > 0) {
            List<TraceNodeParam> parameters = node.getParameters();
            for (TraceNodeParam parameter : parameters) {
                parameter.setParameterValues(JSONObject.toJSONString(parameter.getParameterValues_Obj()));
            }
        }
    }

    /**
     * 获取项目入口层类名&方法名（基于@Api和@ApiOperation注解）
     */
    public List<Entrance_ServiceInfo> getEntranceServiceInfo() {
        List<Entrance_ServiceInfo> entranceServiceInfoList = new ArrayList<>();
        // 获取controller包下的所有类
        Set<Class<?>> classes = ReflectionUtils.getClasses(monitorConfig.getProject_package() + ".controller");

        for (Class<?> clazz : classes) {
            Entrance_ServiceInfo serviceInfo = new Entrance_ServiceInfo();
            // 设置类全限定名
            serviceInfo.setServiceName(clazz.getSimpleName());

            // 处理类上的@Api注解：提取tags或value作为类描述
            if (clazz.isAnnotationPresent(Api.class)) {
                Api apiAnnotation = clazz.getAnnotation(Api.class);
                // 优先取tags（通常tags是功能标签，如"直连公司服务"），若tags为空则取value
                String[] tags = apiAnnotation.tags();
                String serviceDesc = (tags != null && tags.length > 0) ? tags[0] : apiAnnotation.value();
                serviceInfo.setServiceDes(serviceDesc); // 假设Entrance_ServiceInfo有服务描述字段
            }

            // 处理当前类声明的公共方法（过滤父类方法）
            Method[] methods = clazz.getDeclaredMethods();
            for (Method method : methods) {
                // 只处理公共方法且有@ApiOperation注解的方法
                if (Modifier.isPublic(method.getModifiers()) && method.isAnnotationPresent(ApiOperation.class)) {
                    ApiOperation operationAnnotation = method.getAnnotation(ApiOperation.class);
                    Entrance_ServiceInfo.MethodInfo methodInfo = new Entrance_ServiceInfo.MethodInfo();
                    methodInfo.setMethodName(method.getName());
                    // 从@ApiOperation的value获取方法描述（如"获取舱房和价格"）
                    methodInfo.setMethodDes(operationAnnotation.value());
                    serviceInfo.getMethodInfoList().add(methodInfo);
                }
            }

            // 将当前类的信息添加到结果列表
            entranceServiceInfoList.add(serviceInfo);
        }

        return entranceServiceInfoList;
    }
}
